﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using System.IO;
using log4net.Config;
using System.Web;
using System.Xml;

namespace DCT.CodeBox.Log4netWrapper.Codes
{
    /// <summary>
    /// log4net封装类
    /// </summary>
    public class Log4netWrapper
    {
        /// <summary>
        /// 初始化方式
        /// </summary>
        private Action initialConfig = null;
        /// <summary>
        /// logger缓存
        /// </summary>
        private Dictionary<string, ILog> logs = new Dictionary<string, ILog>();
        /// <summary>
        /// 执行初始化配置的lock对象
        /// </summary>
        private object lockExecuteInitConfig = new object();

        /// <summary>
        /// 构造函数
        /// </summary>
        public Log4netWrapper()
        {
            //默认LoggerName为logger
            DefaultLoggerName = "logger";
        }

        /// <summary>
        /// 设置initialConfig，在获取Log之前必须调用一次，并且参数不能为null
        /// </summary>
        /// <param name="initialConfig">初始化log4net的方式</param>
        public void SetInitialConfig(Action initialConfig)
        {
            if (initialConfig == null)
            {
                throw new NullReferenceException("initialConfig is null");
            }
            this.initialConfig = initialConfig;
        }

        /// <summary>
        /// 默认的LoggerName，默认值为logger
        /// </summary>
        public string DefaultLoggerName
        {
            get;
            set;
        }

        /// <summary>
        /// 查看log4net是否已配置
        /// </summary>
        public bool IsConfig
        {
            get
            {
                return LogManager.GetRepository().Configured;
            }
        }

        /// <summary>
        /// 获取logger名称为属性DefaultLoggerName的ILog
        /// </summary>
        /// <returns></returns>
        public ILog GetLogger()
        {
            return this.GetLogger(DefaultLoggerName);
        }

        /// <summary>
        /// 获取logger
        /// </summary>
        /// <param name="loggerName">配置中logger的名称</param>
        /// <returns></returns>
        public ILog GetLogger(string loggerName)
        {
            //如果还没有配置则执行initialConfig
            if (!this.IsConfig)
            {
                if (this.initialConfig == null) //检查initialConfig是否为空
                {
                    throw new NullReferenceException("initialConfig is null, please call SetInitialConfig at first.");
                }
                lock (lockExecuteInitConfig)
                {
                    if (!this.IsConfig) //双检锁
                    {
                        initialConfig();    //执行初始化配置
                        if (!this.IsConfig) //如果初始化配置执行后，还是配置为false，则抛出异常
                        {
                            throw new Exception("initialConfig is not config log4net correctly");
                        }
                    }
                }
            }

            ILog log = null;
            if (logs.ContainsKey(loggerName))
            {
                log = logs[loggerName];
            }

            if (log == null)
            {
                log = LogManager.GetLogger(loggerName);
                logs[loggerName] = log;     //这里不是线性安全，但线程冲突也没关系
            }

            return log;
        }

        #region 常用初始化方式
        /// <summary>
        /// 从一个文件路径初始化
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static Action InitialConfigFromFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("file not found." + filePath);
            }
            return new Action(delegate
            {
                XmlConfigurator.Configure(new FileInfo(filePath));
            });
        }

        /// <summary>
        /// 从一个web路径初始化
        /// </summary>
        /// <param name="webPath"></param>
        /// <returns></returns>
        public static Action InitialConfigFromWebFile(string webPath)
        {
            return InitialConfigFromFile(HttpContext.Current.Server.MapPath(webPath));
        }

        /// <summary>
        /// 从一串xml字符串初始化
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static Action InitialConfigFromXml(string xml)
        {
            XmlDocument doc = Load(xml);
            return new Action(delegate
            {
                XmlConfigurator.Configure(doc.DocumentElement);
            });
        }

        /// <summary>
        /// Xml默认声明
        /// </summary>
        private static string DEFAULT_XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";

        /// <summary>
        /// 加载Xml
        /// </summary>
        /// <param name="xml">xml内容，不允许为空或空字符串</param>
        /// <returns></returns>
        private static XmlDocument Load(string xml)
        {
            if (string.IsNullOrWhiteSpace(xml))
            {
                throw new Exception("xml is null or empty");
            }

            XmlDocument doc = new XmlDocument();
            xml = xml.Trim();

            if (!xml.StartsWith("<?xml version="))
            {
                //自动追加xml
                xml = DEFAULT_XML_DECLARATION + xml;
            }

            doc.LoadXml(xml);

            return doc;
        } 
        #endregion
    }
}
